package com.naiterui.ehp.ps.schedule.service.impl;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.Job;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SimpleTrigger;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.quartz.impl.matchers.GroupMatcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.naiterui.ehp.bp.support.utils.JsonMapper;
import com.naiterui.ehp.ps.schedule.service.IScheduleJobService;
import com.naiterui.ehp.ps.schedule.task.CommonTask;
import com.naiterui.ehp.ps.schedule.vo.ScheduleJobVO;

/**
 * 调度任务Service实现
 *
 * @author Gaoll
 * @since HZD-1.0.0
 */
@Service
public class ScheduleJobServiceImpl implements IScheduleJobService {

    private static final Logger LOGGER = LoggerFactory.getLogger(ScheduleJobServiceImpl.class);

    @Autowired
    private Scheduler scheduler;

    @Override
    public void add(ScheduleJobVO scheduleJobVO) throws SchedulerException {
        JobKey key = new JobKey(scheduleJobVO.getName(), scheduleJobVO.getGroup());
        if (this.scheduler.checkExists(key)) {
            LOGGER.info("该任务已存在:{}", JsonMapper.toJson(scheduleJobVO));
            return;
        }

        String className = scheduleJobVO.getClassName();
        Class<? extends Job> jobClass;
        try {
            jobClass = (Class<? extends Job>) Class.forName(className);
        } catch (ClassNotFoundException e1) {
            throw new SchedulerException(String.format("任务类没有找到 %s", className));
        }
        JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(scheduleJobVO.getName(), scheduleJobVO.getGroup()).build();
        jobDetail.getJobDataMap().put(CommonTask.SCHEDULEJOBVO_NAME, scheduleJobVO);

        // 表达式调度构建器（可判断创建SimpleScheduleBuilder）
        CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJobVO.getCronExpression());

        // 按新的cronExpression表达式构建一个新的trigger
        CronTrigger trigger = TriggerBuilder.newTrigger()
                                            .withIdentity(scheduleJobVO.getName(), scheduleJobVO.getGroup())
                                            .withSchedule(scheduleBuilder)
                                            .build();
        this.scheduler.scheduleJob(jobDetail, trigger);
        LOGGER.info("定时任务添加成功:{}", scheduleJobVO);
    }

    @Override
    public void update(ScheduleJobVO scheduleJobVO) throws SchedulerException {
        JobKey key = new JobKey(scheduleJobVO.getName(), scheduleJobVO.getGroup());
        if (this.scheduler.checkExists(key)) {
            this.scheduler.deleteJob(key);
            String className = scheduleJobVO.getClassName();
            Class<? extends Job> jobClass;
            try {
                jobClass = (Class<? extends Job>)Class.forName(className);
            } catch (ClassNotFoundException e1) {
                throw new SchedulerException(String.format("任务类没有找到 %s", className));
            }
            JobDetail jobDetail =
                JobBuilder.newJob(jobClass).withIdentity(scheduleJobVO.getName(), scheduleJobVO.getGroup()).build();
            jobDetail.getJobDataMap().put(CommonTask.SCHEDULEJOBVO_NAME, scheduleJobVO);

            // 表达式调度构建器（可判断创建SimpleScheduleBuilder）
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJobVO.getCronExpression());

            // 按新的cronExpression表达式构建一个新的trigger
            CronTrigger trigger = TriggerBuilder.newTrigger()
                .withIdentity(scheduleJobVO.getName(), scheduleJobVO.getGroup()).withSchedule(scheduleBuilder).build();
            this.scheduler.scheduleJob(jobDetail, trigger);
            LOGGER.info("定时任务修改成功:{}", scheduleJobVO);
        }
    }

    @Override
    public List<JobDetail> getJobs() throws SchedulerException {
        GroupMatcher<JobKey> matcher = GroupMatcher.anyJobGroup();
        Set<JobKey> jobKeys = this.scheduler.getJobKeys(matcher);
        List<JobDetail> jobDetails = new ArrayList<>();
        for (JobKey key : jobKeys) {
            jobDetails.add(this.scheduler.getJobDetail(key));
        }
        return jobDetails;
    }

    @Override
    public List<ScheduleJobVO> getAllScheduleJob() throws SchedulerException {
        List<ScheduleJobVO> scheduleJobVOList = new ArrayList<>();
        GroupMatcher<JobKey> matcher = GroupMatcher.anyJobGroup();
        Set<JobKey> jobKeys = this.scheduler.getJobKeys(matcher);
        for (JobKey jobKey : jobKeys) {
            List<? extends Trigger> triggers = this.scheduler.getTriggersOfJob(jobKey);
            for (Trigger trigger : triggers) {
                JobDetail jobDetail = this.scheduler.getJobDetail(jobKey);
                ScheduleJobVO scheduleJobVO = (ScheduleJobVO) jobDetail.getJobDataMap().get(CommonTask.SCHEDULEJOBVO_NAME);
                Trigger.TriggerState triggerState = this.scheduler.getTriggerState(trigger.getKey());
                scheduleJobVO.setStatus(triggerState.name());
                // 判断trigger
                if (trigger instanceof SimpleTrigger) {
                    SimpleTrigger simple = (SimpleTrigger) trigger;
                    scheduleJobVO.setCronExpression("重复次数:" + (simple.getRepeatCount() == -1 ? "无限" : simple.getRepeatCount()) + ",重复间隔:"
                                                            + (simple.getRepeatInterval() / 1000L));
                    scheduleJobVO.setDescription(simple.getDescription());
                }
                if (trigger instanceof CronTrigger) {
                    CronTrigger cron = (CronTrigger) trigger;
                    scheduleJobVO.setCronExpression(cron.getCronExpression());
                    scheduleJobVO.setDescription(cron.getDescription() == null ? ("触发器:" + trigger.getKey()) : cron.getDescription());
                }
                scheduleJobVOList.add(scheduleJobVO);
            }
        }
        return scheduleJobVOList;
    }

    @Override
    public List<ScheduleJobVO> getAllRuningScheduleJob() throws SchedulerException {
        List<JobExecutionContext> executingJobs = this.scheduler.getCurrentlyExecutingJobs();
        List<ScheduleJobVO> scheduleJobVOList = new ArrayList<>(executingJobs.size());
        for (JobExecutionContext executingJob : executingJobs) {
            ScheduleJobVO scheduleJobVO = new ScheduleJobVO();
            JobDetail jobDetail = executingJob.getJobDetail();
            JobKey jobKey = jobDetail.getKey();
            Trigger trigger = executingJob.getTrigger();
            scheduleJobVO.setName(jobKey.getName());
            scheduleJobVO.setGroup(jobKey.getGroup());
            Trigger.TriggerState triggerState = this.scheduler.getTriggerState(trigger.getKey());
            scheduleJobVO.setStatus(triggerState.name());
            // 获取要执行的定时任务类名
            scheduleJobVO.setClassName(jobDetail.getJobClass().getName());
            // 判断trigger
            if (trigger instanceof SimpleTrigger) {
                SimpleTrigger simple = (SimpleTrigger) trigger;
                scheduleJobVO.setCronExpression("重复次数:" + (simple.getRepeatCount() == -1 ? "无限" : simple.getRepeatCount()) + ",重复间隔:"
                                                        + (simple.getRepeatInterval() / 1000L));
                scheduleJobVO.setDescription(simple.getDescription());
            }
            if (trigger instanceof CronTrigger) {
                CronTrigger cron = (CronTrigger) trigger;
                scheduleJobVO.setCronExpression(cron.getCronExpression());
                scheduleJobVO.setDescription(cron.getDescription());
            }
            scheduleJobVOList.add(scheduleJobVO);
        }
        return scheduleJobVOList;
    }

    @Override
    public List<ScheduleJobVO> getTriggersInfo() throws SchedulerException {
        GroupMatcher<TriggerKey> matcher = GroupMatcher.anyTriggerGroup();
        Set<TriggerKey> keys = this.scheduler.getTriggerKeys(matcher);
        List<ScheduleJobVO> triggers = new ArrayList<>();

        for (TriggerKey key : keys) {
            Trigger trigger = this.scheduler.getTrigger(key);
            ScheduleJobVO scheduleJobVO = new ScheduleJobVO();
            scheduleJobVO.setName(trigger.getJobKey().getName());
            scheduleJobVO.setGroup(trigger.getJobKey().getGroup());
            scheduleJobVO.setStatus(this.scheduler.getTriggerState(key) + "");
            if (trigger instanceof SimpleTrigger) {
                SimpleTrigger simple = (SimpleTrigger) trigger;
                scheduleJobVO.setCronExpression("重复次数:" + (simple.getRepeatCount() == -1 ? "无限" : simple.getRepeatCount()) + ",重复间隔:"
                                                        + (simple.getRepeatInterval() / 1000L));
                scheduleJobVO.setDescription(simple.getDescription());
            }
            if (trigger instanceof CronTrigger) {
                CronTrigger cron = (CronTrigger) trigger;
                scheduleJobVO.setCronExpression(cron.getCronExpression());
                scheduleJobVO.setDescription(cron.getDescription());
            }
            triggers.add(scheduleJobVO);
        }
        return triggers;
    }

    @Override
    public void stopJob(String name, String group) throws SchedulerException {
        JobKey key = new JobKey(name, group);
        this.scheduler.pauseJob(key);
    }

    @Override
    public void restartJob(String name, String group) throws SchedulerException {

        // 用更换cron表达式的方式，避免暂停任务后，重新启动，暂停任务期间符合定cron定时器表达式的任务点会被全部激活执行
        TriggerKey key = TriggerKey.triggerKey(name, group);

        Trigger trigger = this.scheduler.getTrigger(key);
        CronTrigger cronTrigger = (CronTrigger) trigger;
        String cron = cronTrigger.getCronExpression();
        CronTrigger newTrigger = TriggerBuilder.newTrigger().withIdentity(key).withSchedule(CronScheduleBuilder.cronSchedule(cron)).build();
        this.scheduler.rescheduleJob(key, newTrigger);

    }

    @Override
    public void startNowJob(String name, String group) throws SchedulerException {
        JobKey jobKey = JobKey.jobKey(name, group);
        this.scheduler.triggerJob(jobKey);
    }

    @Override
    public void deleteJob(String name, String group) throws SchedulerException {
        JobKey key = new JobKey(name, group);
        if (this.scheduler.checkExists(key)) {
            this.scheduler.deleteJob(key);
        }
    }

    @Override
    public void modifyTrigger(String name, String group, String cron) throws SchedulerException {
        TriggerKey key = TriggerKey.triggerKey(name, group);
        CronTrigger newTrigger = TriggerBuilder.newTrigger().withIdentity(key).withSchedule(CronScheduleBuilder.cronSchedule(cron)).build();
        this.scheduler.rescheduleJob(key, newTrigger);
    }

    @Override
    public void stopScheduler() throws SchedulerException {
        if (!this.scheduler.isInStandbyMode()) {
            this.scheduler.standby();
        }
    }

}
